package ca.cbc.medialib.entity;

import org.hibernate.annotations.AccessType;

import javax.persistence.*;
import javax.xml.bind.annotation.*;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;


/**
 * @author Arash Bizhanzadeh <arash.bizhan-zadeh@cbc.ca>
 *         Date: 31/12/10
 *         Time: 11:16 AM
 *         Copyrighted to CBC. All rights reserved.
 */

@XmlRootElement
@XmlAccessorType(XmlAccessType.NONE)
@Entity
public class Media implements Serializable {
    /*
    * Build cannot assign value to collection
    */
    @XmlTransient
    public static class Builder {

        public static Builder getBuilder() {
            return new Builder();
        }

        private String subtitle;
        private long releaseId;                        //release
        private long id;                                //media
        private String title;                        //media
        private String description;                    //media
        private long mobileId;                        //release-custom
        private Date airDate;                        //media
        private String genre;                        //media-custom
        private String keywords;                    //media
        private String thumbnailUrl;                //media
        private Date availableDate;                    //media
        private Date unapprovedDate;
        private String seasonNumber;                //media-custom
        private String episodeNumber;                //media-custom
        private Date mobileExpiryDate;
        private String length;                        //media
        private String adCategory;                    //media-custom
        private String delivery;                    //release
        private String releaseUrl;                    //release
        private String audioVideo;                    //media-custom
        private String liveOndemand;                //media-custom
        private String availableInMobile;            //media-custom
        private String show;                        //media-custom
        private String chapterStartTimes;            //media-custom
        private String originalFileName;            //media-custom
        private boolean excludeCountries;
        private String countries;
        private String account;
        private String streamingCategoryFullTitle;
        private String adRules;
        private boolean approved;

        public Media buildNew() {
            Media m = new Media(releaseId, id, title, description, mobileId, airDate, genre, keywords,
                    thumbnailUrl, availableDate, unapprovedDate, seasonNumber, episodeNumber, mobileExpiryDate, length,
                    adCategory, delivery, releaseUrl, audioVideo, liveOndemand, availableInMobile, show,
                    chapterStartTimes, originalFileName, excludeCountries, countries, account,
                    streamingCategoryFullTitle, subtitle, adRules, approved);
            return m;
        }

        public Builder withAccount(String account) {
            this.account = account;
            return this;
        }
        
        public Builder withAdCategory(String adCategory) {
            this.adCategory = adCategory;
            return this;
        }

        public Builder withAdRules ( String s ){
            adRules = s;
            return this;
        }

        public Builder withAirDate(Date airDate) {
            this.airDate = airDate;
            return this;
        }

        public Builder withApproved(boolean approved) {
        	this.approved = approved;
        	return this;
        }

        public Builder withAudioVideo(String audioVideo) {
            this.audioVideo = audioVideo;
            return this;
        }

        public Builder withAvailableDate(Date availableDate) {
            this.availableDate = availableDate;
            return this;
        }
        
        public Builder withAvailableInMobile(String availableInMobile) {
            this.availableInMobile = availableInMobile;
            return this;
        }

        public Builder withChapterStartTimes(String chapterStartTimes) {
            this.chapterStartTimes = chapterStartTimes;
            return this;
        }

        public Builder withCountries(String countries) {
            this.countries = countries;
            return this;
        }

        public Builder withDelivery(String delivery) {
            this.delivery = delivery;
            return this;
        }

        public Builder withDescription(String description) {
            this.description = description;
            return this;
        }

        public Builder withEpisodeNumber(String episodeNumber) {
            this.episodeNumber = episodeNumber;
            return this;
        }

        public Builder withExcludeCountries(boolean excludeCountries) {
            this.excludeCountries = excludeCountries;
            return this;
        }

        public Builder withGenre(String genre) {
            this.genre = genre;
            return this;
        }

        public Builder withId(long id) {
            this.id = id;
            return this;
        }

        public Builder withKeywords(String keywords) {
            this.keywords = keywords;
            return this;
        }

        public Builder withLength(String length) {
            this.length = length;
            return this;
        }

        public Builder withLiveOndemand(String liveOndemand) {
            this.liveOndemand = liveOndemand;
            return this;
        }

        public Builder withMobileExpiryDate(Date mobileExpiryDate) {
            this.mobileExpiryDate = mobileExpiryDate;
            return this;
        }

        public Builder withMobileId(long mobileId) {
            this.mobileId = mobileId;
            return this;
        }

        public Builder withOriginalFileName(String originalFileName) {
            this.originalFileName = originalFileName;
            return this;
        }

        public Builder withReleaseId(long releaseId) {
            this.releaseId = releaseId;
            return this;
        }

        public Builder withReleaseUrl(String releaseUrl) {
            this.releaseUrl = releaseUrl;
            return this;
        }

        public Builder withSeasonNumber(String seasonNumber) {
            this.seasonNumber = seasonNumber;
            return this;
        }

        public Builder withShow(String show) {
            this.show = show;
            return this;
        }

        public Builder withStreamingCategoryFullTitle(String streamingCategoryFullTitle) {
            this.streamingCategoryFullTitle = streamingCategoryFullTitle;
            return this;
        }

        public Builder withSubtitle( String s){
            this.subtitle = s;
            return this;
        }

        public Builder withThumbnailUrl(String thumbnailUrl) {
            this.thumbnailUrl = thumbnailUrl;
            return this;
        }

        public Builder withTitle(String title) {
            this.title = title;
            return this;
        }

        public Builder withUnapprovedDate(Date unapprovedDate) {
            this.unapprovedDate = unapprovedDate;
            return this;
        }
    }

    private static final long serialVersionUID = -2084263582406317757L;
    private long releaseId;        //release Id
    @XmlAttribute
    private long id;        //media Id
    @XmlElement
    private String title;
    @XmlElement
    private String description;
    @XmlElement
    private long mobileId;
    @XmlElement
    private Date airDate;
    @XmlElement
    private String genre;
    @XmlElement
    private String keywords;
    @XmlElement
    private String thumbnailUrl;
    @XmlElement
    private Date availableDate;
    private Date unapprovedDate;
    @XmlElement
    private String seasonNumber;
    @XmlElement
    private String episodeNumber;
    @XmlElement
    private Date mobileExpiryDate;

    @XmlElement
    private String length;
    @XmlElementWrapper(name = "categories")
    @XmlElement(name = "category")
    private List<Category> categories;
    @XmlElement
    private String adCategory;
    @XmlElement
    private String account;
    /*
    * Following attributes are not need for XML feed
    */
    private String streamingCategoryFullTitle;
    private String delivery;     //download or streaming
    private String releaseUrl;

    private String audioVideo;
    private String liveOndemand;
    private String availableInMobile;
    private String show;        //show name e.g. NHIC
    private String chapterStartTimes;            //media-customs   
    private String originalFileName;            //media
    /*
     * Following attributes are not need for db and XML
     */
    private boolean excludeCountries;        //true means allow playback in geo-restriction countries
    private String countries;
    private String subtitle;
    private String adRules;
    private boolean approved;

    private Media() {
        this.categories = new ArrayList<Category>();
    }

	public Media(long releaseId, long id, String title, String description, long mobileId, Date airDate,
                 String genre, String keywords, String thumbnailUrl, Date availableDate, Date unapprovedDate, 
                 String seasonNumber, String episodeNumber, Date mobileExpiryDate, String length, String adCategory, 
                 String delivery, String releaseUrl, String audioVideo, String liveOndemand, String availableInMobile,
                 String show, String chapterStartTimes, String originalFileName, boolean excludeCountries, String countries,
                 String account, String streamingCategoryFullTitle, String subtitle, String adRules, boolean approved) {
        this();
        this.releaseId = releaseId;
        this.id = id;
        this.title = title;
        this.description = description;
        this.mobileId = mobileId;
        this.airDate = airDate;
        this.genre = genre;
        this.keywords = keywords;
        this.thumbnailUrl = thumbnailUrl;
        this.setAvailableDate(availableDate);
        this.setUnapprovedDate(unapprovedDate);     
        this.seasonNumber = seasonNumber;
        this.episodeNumber = episodeNumber;
        this.mobileExpiryDate = mobileExpiryDate;
        this.length = length;
        this.adCategory = adCategory;
        this.delivery = delivery;
        this.releaseUrl = releaseUrl;
        this.audioVideo = audioVideo;
        this.liveOndemand = liveOndemand;
        this.availableInMobile = availableInMobile;
        this.show = show;
        this.chapterStartTimes = chapterStartTimes;
        this.originalFileName = originalFileName;
        this.countries = countries;
        this.excludeCountries = excludeCountries;
        this.account = account;
        this.streamingCategoryFullTitle = streamingCategoryFullTitle;
        this.subtitle = subtitle;
        this.adRules = adRules;
        this.setApproved(approved);
    }

    public void addCategory(Category category) {
        this.categories.add(category);
        category.internallAddMedia(this);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Media media = (Media) o;
        return !(this.getId() != media.getId() || this.getReleaseId() != media.getReleaseId()
                || this.getMobileId() != media.getMobileId());

    }

    public String getAccount() {
        return account;
    }

    @Column(name = "ad_category")
    public String getAdCategory() {
        return adCategory;
    }

    @Column(name= "ad_rules")
    public String getAdRules() {
        return adRules;
    }

    @Column(name = "air_date")
    public Date getAirDate() {
        return airDate;
    }
    
    @Column(columnDefinition="bool default true")
    public boolean getApproved() {
        return approved;
    }

    @Column(name = "audio_video")
    public String getAudioVideo() {
        return audioVideo;
    }

    @Column(name = "available_date")
    public Date getAvailableDate() {
        return availableDate;
    }

    @Column(name = "available_in_mobile")
    public String getAvailableInMobile() {
        return availableInMobile;
    }

    @ManyToMany
    @JoinTable(name = "category_media",
            joinColumns = {@JoinColumn(name = "release_id")},
            inverseJoinColumns = {@JoinColumn(name = "category_id")})
    @AccessType("field")
    public List<Category> getCategories() {
        return categories;
    }

    @Column(name = "chapter_start_times")
    public String getChapterStartTimes() {
        return chapterStartTimes;
    }

    public String getCountries() {
        return countries;
    }

    public String getDelivery() {
        return delivery;
    }

    public String getDescription() {
        return description;
    }

    @Column(name = "episode_number")
    public String getEpisodeNumber() {
        return episodeNumber;
    }

    @Column(name = "exclude_countries")
    public boolean getExcludeCountries() {
        return excludeCountries;
    }

    public String getGenre() {
        return genre;
    }

    @Column(name = "media_id")
    public long getId() {
        return id;
    }

    public String getKeywords() {
        return keywords;
    }

    public String getLength() {
        return length;
    }

    @Column(name = "live_ondemand")
    public String getLiveOndemand() {
        return liveOndemand;
    }

    @Column(name = "expiry_date")
    public Date getMobileExpiryDate() {
        return mobileExpiryDate;
    }

    @Column(name = "yospace_id")
    public long getMobileId() {
        return mobileId;
    }

    @Column(name = "original_filename")
    public String getOriginalFileName() {
        return originalFileName;
    }

    @Id
    @Column(name = "release_id")
    public long getReleaseId() {
        return releaseId;
    }

    @Column(name = "release_url")
    public String getReleaseUrl() {
        return releaseUrl;
    }

    @Column(name = "season_number")
    public String getSeasonNumber() {
        return seasonNumber;
    }

    @Column(name = "show_name")
    public String getShow() {
        return show;
    }

    @Column(name = "streaming_category_fulltitle")
    public String getStreamingCategoryFullTitle() {
        return streamingCategoryFullTitle;
    }

    public String getSubtitle() {
        return subtitle;
    }

    @Column(name = "thumbnail_url")
    public String getThumbnailUrl() {
        return thumbnailUrl;
    }

    public String getTitle() {
        return title;
    }

    @Column(name = "unapproved_date")
    public Date getUnapprovedDate() {
		return unapprovedDate;
	}

    @Override
    public int hashCode() {
        int result = title != null ? title.hashCode() : (int) (id % 1000l);
        result = 31 * result;
        return result;
    }

    public void removeAllCategories() {
        this.categories = new ArrayList<Category>();
    }

    public void removeCategory(Category category) {
        this.categories.remove(category);
        category.internallRemoveMedia(this);
    }

    public void setAccount(String account) {
        this.account = account;
    }

    public void setAdCategory(String adCategory) {
        this.adCategory = adCategory;
    }

    public void setAdRules(String adRules) {
        this.adRules = adRules;
    }

    public void setAirDate(Date airDate) {
        this.airDate = airDate;
    }

    public void setApproved(boolean approved) {
		this.approved = approved;
	}

    public void setAudioVideo(String audioVideo) {
        this.audioVideo = audioVideo;
    }

    public void setAvailableDate(Date availableDate) {
        this.availableDate = availableDate;
    }

    public void setAvailableInMobile(String availableInMobile) {
        this.availableInMobile = availableInMobile;
    }

    public void setChapterStartTimes(String chapterStartTimes) {
        this.chapterStartTimes = chapterStartTimes;
    }

    public void setCountries(String countries) {
        this.countries = countries;
    }

    public void setDelivery(String delivery) {
        this.delivery = delivery;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public void setEpisodeNumber(String episodeNumber) {
        this.episodeNumber = episodeNumber;
    }

    public void setExcludeCountries(boolean excludeCountries) {
        this.excludeCountries = excludeCountries;
    }

    public void setGenre(String genre) {
        this.genre = genre;
    }

    public void setId(long id) {
        this.id = id;
    }

    public void setKeywords(String keywords) {
        this.keywords = keywords;
    }

    public void setLength(String length) {
        this.length = length;
    }

    public void setLiveOndemand(String liveOndemand) {
        this.liveOndemand = liveOndemand;
    }

    public void setMobileExpiryDate(Date mobileExpiryDate) {
        this.mobileExpiryDate = mobileExpiryDate;
    }

    public void setMobileId(long mobileId) {
        this.mobileId = mobileId;
    }

    public void setOriginalFileName(String originalFileName) {
        this.originalFileName = originalFileName;
    }

    public void setReleaseId(long releaseId) {
        this.releaseId = releaseId;
    }

    public void setReleaseUrl(String releaseUrl) {
        this.releaseUrl = releaseUrl;
    }

    public void setSeasonNumber(String seasonNumber) {
        this.seasonNumber = seasonNumber;
    }


    public void setShow(String show) {
        this.show = show;
    }

    public void setStreamingCategoryFullTitle(String streamingCategoryFullTitle) {
        this.streamingCategoryFullTitle = streamingCategoryFullTitle;
    }

    public void setSubtitle(String subtitle) {
        this.subtitle = subtitle;
    }

    public void setThumbnailUrl(String thumbnailUrl) {
        this.thumbnailUrl = thumbnailUrl;
    }

    public void setTitle(String title) {
        this.title = title;
    }

	public void setUnapprovedDate(Date unapprovedDate) {
		this.unapprovedDate = unapprovedDate;
	}

	@Override
    public String toString() {
        final StringBuilder sb = new StringBuilder();
        sb.append("Media");
        sb.append("{id=").append(id);
        sb.append(", releaseId=").append(releaseId);
        sb.append(", title='").append(title).append('\'');
        sb.append(", genre='").append(genre).append('\'');
        sb.append(", mobileId=").append(mobileId);
        sb.append(", adCategory='").append(adCategory).append('\'');
        sb.append(", mobileExpiryDate=").append(mobileExpiryDate);
        sb.append(", chapterStartTimes='").append(chapterStartTimes).append('\'');
        sb.append(", delivery='").append(delivery).append('\'');
        sb.append('}');
        return sb.toString();
    }
}
